package dfferber.xstream;

/*
 * Copyright (C) 2005, 2006 Joe Walnes.
 * Copyright (C) 2006, 2007, 2008 XStream Committers.
 * All rights reserved.
 *
 * The software in this package is published under the terms of the BSD
 * style license a copy of which has been included with this distribution in
 * the LICENSE.txt file.
 * 
 * Created on 22. January 2005 by Joe Walnes
 */

import com.thoughtworks.xstream.alias.ClassMapper;
import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.SingleValueConverter;
import com.thoughtworks.xstream.mapper.Mapper;
import com.thoughtworks.xstream.mapper.Mapper.ImplicitCollectionMapping;

public class TwoMapperCompareWrapper implements Mapper {

	private final Mapper wrapped1;
	private final Mapper wrapped2;

	public TwoMapperCompareWrapper(Mapper wrapped1, Mapper wrapped2) {
		this.wrapped1 = wrapped1;
		this.wrapped2 = wrapped2;
	}

	public String serializedClass(Class type) {
		String item1 = wrapped1.serializedClass(type);
		String item2 = wrapped2.serializedClass(type);
		if (diferente(item1, item2)) {
			System.out.println("serializedClass: " + type.toString() + " = " + item1 + " " + item2);
		}
		return item1;
	}

	public Class realClass(String elementName) {
		Class item1 = wrapped1.realClass(elementName);
		Class item2 = wrapped2.realClass(elementName);
		if (diferente(item1, item2)) {
			System.out.println("realClass: " + elementName.toString() + " = " + item1 + " " + item2);
		}
		return item1;
	}

	public String serializedMember(Class type, String memberName) {
		String item1 = wrapped1.serializedMember(type, memberName);
		String item2 = wrapped2.serializedMember(type, memberName);
		if (diferente(item1, item2)) {
			System.out.println("serializedMember: " + type.toString() + memberName.toString() + " "+ " = " + item1 + " " + item2);
		}
		return item1;
	}

	public String realMember(Class type, String serialized) {
		String item1 = wrapped1.realMember(type, serialized);
		String item2 = wrapped2.realMember(type, serialized);
		if (diferente(item1, item2)) {
			System.out.println("realMember: " + type.toString() + serialized.toString() + " "+ " = " + item1 + " " + item2);
		}
		return item1;
	}

	public boolean isImmutableValueType(Class type) {
		boolean item1 = wrapped1.isImmutableValueType(type);
		boolean item2 = wrapped2.isImmutableValueType(type);
		if (item1 != item2) {
			System.out.println("isImmutableValueType: " + type.toString() + " = " + item1 + " " + item2);
		}
		return item1;
	}

	public Class defaultImplementationOf(Class type) {
		Class item1 = wrapped1.defaultImplementationOf(type);
		Class item2 = wrapped2.defaultImplementationOf(type);
		if (diferente(item1, item2)) {
			System.out.println("defaultImplementationOf: " + type.toString() + " = " + item1 + " " + item2);
		}
		return item1;
	}

	/**
	 * @deprecated since 1.2, use aliasForAttribute instead.
	 */
	public String attributeForClassDefiningField() {
		String item1 = wrapped1.attributeForClassDefiningField();
		String item2 = wrapped2.attributeForClassDefiningField();
		if (diferente(item1, item2)) {
			System.out.println("attributeForClassDefiningField: " +  " = " + item1 + " " + item2);
		}
		return item1;
	}

	/**
	 * @deprecated since 1.2, use aliasForAttribute instead.
	 */
	public String attributeForImplementationClass() {
		String item1 = wrapped1.attributeForImplementationClass();
		String item2 = wrapped2.attributeForImplementationClass();
		if (diferente(item1, item2)) {
			System.out.println("attributeForImplementationClass: " + " = " + item1 + " " + item2);
		}
	return item1;
	}

	/**
	 * @deprecated since 1.2, use aliasForAttribute instead.
	 */
	public String attributeForReadResolveField() {
		String item1 = wrapped1.attributeForReadResolveField();
		String item2 = wrapped2.attributeForReadResolveField();
		if (diferente(item1, item2)) {
			System.out.println("attributeForReadResolveField: " +  " = " + item1 + " " + item2);
		}
		return item1;
	}

	/**
	 * @deprecated since 1.2, use aliasForAttribute instead.
	 */
	public String attributeForEnumType() {
		String item1 = wrapped1.attributeForEnumType();
		String item2 = wrapped2.attributeForEnumType();
		if (diferente(item1, item2)) {
			System.out.println("attributeForEnumType: " + " = " + item1 + " " + item2);
		}
		return item1;
	}

	public String aliasForAttribute(String attribute) {
		String item1 = wrapped1.aliasForAttribute(attribute);
		String item2 = wrapped2.aliasForAttribute(attribute);
		if (diferente(item1, item2)) {
			System.out.println("aliasForAttribute: " + attribute.toString() + " = " + item1 + " " + item2);
		}
		return item1;
	}

	public String attributeForAlias(String alias) {
		String item1 = wrapped1.attributeForAlias(alias);
		String item2 = wrapped2.attributeForAlias(alias);
		if (diferente(item1, item2)) {
			System.out.println("attributeForAlias: " + alias.toString() + " = " + item1 + " " + item2);
		}
		return item1;
	}

	public String aliasForSystemAttribute(String attribute) {
		String item1 = wrapped1.aliasForSystemAttribute(attribute);
		String item2 = wrapped2.aliasForSystemAttribute(attribute);
		if (diferente(item1, item2)) {
			System.out.println("aliasForSystemAttribute: " + attribute.toString() + " = " + item1 + " " + item2);
		}
		return item1;
	}

	public String getFieldNameForItemTypeAndName(Class definedIn, Class itemType, String itemFieldName) {
		String item1 = wrapped1.getFieldNameForItemTypeAndName(definedIn, itemType, itemFieldName);
		String item2 = wrapped2.getFieldNameForItemTypeAndName(definedIn, itemType, itemFieldName);
		if (diferente(item1, item2)) {
			System.out.println("getFieldNameForItemTypeAndName: " + definedIn.toString() + " "+ itemType.toString() + itemFieldName.toString() + " "+ " = " + item1 + " " + item2);
		}
		return item1;
	}

	public Class getItemTypeForItemFieldName(Class definedIn, String itemFieldName) {
		Class item1 = wrapped1.getItemTypeForItemFieldName(definedIn, itemFieldName);
		Class item2 = wrapped2.getItemTypeForItemFieldName(definedIn, itemFieldName);
		if (diferente(item1, item2)) {
			System.out.println("getItemTypeForItemFieldName: " + definedIn.toString() + " "+ itemFieldName.toString() + " = " + item1 + " " + item2);
		}
		return item1;
	}

	public ImplicitCollectionMapping getImplicitCollectionDefForFieldName(Class itemType, String fieldName) {
		ImplicitCollectionMapping item1 = wrapped1.getImplicitCollectionDefForFieldName(itemType, fieldName);
		ImplicitCollectionMapping item2 = wrapped2.getImplicitCollectionDefForFieldName(itemType, fieldName);
		if (diferente(item1, item2)) {
			System.out.println("getImplicitCollectionDefForFieldName: " + itemType.toString() + " "+ fieldName.toString() + " = " + item1 + " " + item2);
		}
		return item1;
	}

	public boolean shouldSerializeMember(Class definedIn, String fieldName) {
		boolean item1 = wrapped1.shouldSerializeMember(definedIn, fieldName);
		boolean item2 = wrapped2.shouldSerializeMember(definedIn, fieldName);
		if (item1 != item2) {
			System.out.println("shouldSerializeMember: " + definedIn.toString() + " "+ fieldName.toString() + " = " + item1 + " " + item2);
		}
		return item1;
	}

	/**
	 * @deprecated since 1.3, use
	 *             {@link #getConverterFromItemType(String, Class, Class)}
	 */
	public SingleValueConverter getConverterFromItemType(String fieldName, Class type) {
		SingleValueConverter item1 = wrapped1.getConverterFromItemType(fieldName, type);
		SingleValueConverter item2 = wrapped2.getConverterFromItemType(fieldName, type);
		if (diferente(item1, item2)) {
			System.out.println("getConverterFromItemType: " + fieldName.toString() + " "+ type.toString() + " = " + item1 + " " + item2);
		}
		return item1;
	}

	/**
	 * @deprecated since 1.3, use
	 *             {@link #getConverterFromItemType(String, Class, Class)}
	 */
	public SingleValueConverter getConverterFromItemType(Class type) {
		SingleValueConverter item1 = wrapped1.getConverterFromItemType(type);
		SingleValueConverter item2 = wrapped2.getConverterFromItemType(type);
		if (diferente(item1, item2)) {
			System.out.println("getConverterFromItemType: " + type.toString() + " = " + item1 + " " + item2);
		}
		return item1;
	}

	/**
	 * @deprecated since 1.3, use
	 *             {@link #getConverterFromAttribute(Class, String, Class)}
	 */
	public SingleValueConverter getConverterFromAttribute(String name) {
		SingleValueConverter item1 = wrapped1.getConverterFromAttribute(name);
		SingleValueConverter item2 = wrapped2.getConverterFromAttribute(name);
		if (diferente(item1, item2)) {
			System.out.println("getConverterFromAttribute: " + name.toString() + " = " + item1 + " " + item2);
		}
		return item1;
	}

	public Converter getLocalConverter(Class definedIn, String fieldName) {
		Converter item1 = wrapped1.getLocalConverter(definedIn, fieldName);
		Converter item2 = wrapped2.getLocalConverter(definedIn, fieldName);
		if (diferente(item1, item2)) {
			System.out.println("getLocalConverter: "+ definedIn.toString() + " " + fieldName.toString() + " = " + item1 + " " + item2);
		}
		return item1;
	}

	public Mapper lookupMapperOfType(Class type) {
		Mapper item1 = type.isAssignableFrom(getClass()) ? this : wrapped1.lookupMapperOfType(type);
		Mapper item2 = type.isAssignableFrom(getClass()) ? this : wrapped2.lookupMapperOfType(type);
		if (diferente(item1, item2)) {
			System.out.println("lookupMapperOfType: " + type.toString() + " = " + item1 + " " + item2);
			item1 = type.isAssignableFrom(getClass()) ? this : wrapped1.lookupMapperOfType(type);
			item2 = type.isAssignableFrom(getClass()) ? this : wrapped2.lookupMapperOfType(type);
		}
		return item1;
	}

	public SingleValueConverter getConverterFromItemType(String fieldName, Class type, Class definedIn) {
		SingleValueConverter item1 = wrapped1.getConverterFromItemType(fieldName, type, definedIn);
		SingleValueConverter item2 = wrapped2.getConverterFromItemType(fieldName, type, definedIn);
		if (diferente(item1, item2)) {
			System.out.println("getConverterFromItemType: " + fieldName.toString() + " "+ type.toString() + definedIn.toString() + " "+ " = " + item1 + " " + item2);
		}
		return item1;
	}

	/**
	 * @deprecated since 1.3, use combination of
	 *             {@link #serializedMember(Class, String)} and
	 *             {@link #getConverterFromItemType(String, Class, Class)}
	 */
	public String aliasForAttribute(Class definedIn, String fieldName) {
		String item1 = wrapped1.aliasForAttribute(definedIn, fieldName);
		String item2 = wrapped2.aliasForAttribute(definedIn, fieldName);
		if (diferente(item1, item2)) {
			System.out.println("aliasForAttribute: " + definedIn.toString() + " " + fieldName.toString() + " = " + item1 + " " + item2);
		}
		return item1;
	}

	/**
	 * @deprecated since 1.3, use combination of
	 *             {@link #realMember(Class, String)} and
	 *             {@link #getConverterFromItemType(String, Class, Class)}
	 */
	public String attributeForAlias(Class definedIn, String alias) {
		String item1 = wrapped1.attributeForAlias(definedIn, alias);
		String item2 = wrapped2.attributeForAlias(definedIn, alias);
		if (diferente(item1, item2)) {
			System.out.println("attributeForAlias: " + definedIn.toString() + " "+ alias.toString() + " = " + item1 + " " + item2);
		}
		return item1;
	}

	/**
	 * @deprecated since 1.3.1, use
	 *             {@link #getConverterFromAttribute(Class, String, Class)}
	 */
	public SingleValueConverter getConverterFromAttribute(Class type, String attribute) {
		SingleValueConverter item1 = wrapped1.getConverterFromAttribute(type, attribute);
		SingleValueConverter item2 = wrapped2.getConverterFromAttribute(type, attribute);
		if (diferente(item1, item2)) {
			System.out.println("getConverterFromAttribute: " + type.toString() + " " + attribute+ " = " + item1 + " " + item2);
		}
		return item1;
	}

	public SingleValueConverter getConverterFromAttribute(Class definedIn, String attribute, Class type) {
		SingleValueConverter item1 = wrapped1.getConverterFromAttribute(definedIn, attribute, type);
		SingleValueConverter item2 = wrapped2.getConverterFromAttribute(definedIn, attribute, type);
		if (diferente(item1, item2)) {
			System.out.println("getConverterFromAttribute: " + definedIn.toString() + " " + attribute+ " " + type.toString() + " = " + item1 + " " + item2);
		}
		return item1;
	}

	private boolean diferente(Object item1, Object item2) {
		if (item1 == item2 ) return false;
		if (item1 == null && item2 != null ) return true;
		if (item2 == null && item1 != null ) return true;
		return ! item1.equals(item2);
	}

}
